package com.blank.shop.ssr.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 抢红包小游戏
 * <br/>Date 2021/9/7
 * <br/>Time 21:49:24
 *
 * @author _blank
 */
@Slf4j
@RestController
public class RedPackageController {

    /**
     * 发红包
     */
    public static final String RED_PACKAGE_KEY = "redpackage:";
    /**
     * 抢红包
     */
    public static final String RED_PACKAGE_CONSUME_KEY = "redpackage:consume:";

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 发红包
     *
     *
     * 金额必须用    java.math.BigDecimal    防止丢失精度
     * 金额必须用    java.math.BigDecimal    防止丢失精度
     * 金额必须用    java.math.BigDecimal    防止丢失精度
     */
    @GetMapping(path = {"send"})
    public ResponseEntity<String> sendRedPackage(Integer totalMoney, Integer redPackageNumber) {
        // 总金额
        Assert.notNull(totalMoney, "总金额不能为null");
        // 红包个数
        Assert.notNull(redPackageNumber, "红包个数不能为null");

        // [拆分好的金额] 拆红包，总金额拆分成多少个红包，每个小红包里面包多少钱
        final Integer[] redPackageNumbers = new Integer[redPackageNumber];

        // 二倍均值法拆包
        // 拆完红包总金额+每个小红包金额别太离谱
        int useMoney = 0;
        for (int i = 0; i < redPackageNumber; i++) {
            if (i == redPackageNumber - 1) {
                redPackageNumbers[i] = totalMoney - useMoney;
            } else {
                final int avgMoney = (totalMoney - useMoney) * 2 / (redPackageNumber - i);
                redPackageNumbers[i] = 1 + RandomUtil.randomInt(avgMoney - 1);
            }
            useMoney = useMoney + redPackageNumbers[i];
        }

        // 红包的全局ID
        final String key = RED_PACKAGE_KEY + IdUtil.simpleUUID();

        // 采用list存储红包并设置过期时间
        this.redisTemplate.opsForList().leftPushAll(key, redPackageNumbers);
        this.redisTemplate.expire(key, 1, TimeUnit.DAYS);

        return ResponseEntity.ok(key + "  :  " + Arrays.toString(redPackageNumbers));
    }

    /**
     * 抢红包
     */
    @GetMapping(path = {"/rob"})
    public ResponseEntity<Object> rodRedPackage(String redPackageKey, String userId) {
        // 验证某个用户是否抢过红包
        final Object redPackage = this.redisTemplate.opsForHash().get(RED_PACKAGE_CONSUME_KEY + redPackageKey, userId);
        // 没有抢过就开抢，否则返回-2表示抢过
        if (Objects.isNull(redPackage)) {
            // 从list里面出队一个红包，抢到了一个
            Object partRedPackage = this.redisTemplate.opsForList().leftPop(RED_PACKAGE_KEY + redPackageKey);
            if (Objects.nonNull(partRedPackage)) {
                //2.2 抢到手后，记录进去hash表示谁抢到了多少钱的某一个红包
                this.redisTemplate.opsForHash().put(RED_PACKAGE_CONSUME_KEY + redPackageKey, userId, partRedPackage);
                //TODO 后续异步进mysql或者RabbitMQ进一步处理
                return ResponseEntity.ok("用户: " + userId + "\t 抢到多少钱红包: " + partRedPackage);
            }
            // 抢完
            return ResponseEntity.ok("errorCode:-1,红包抢完了");
        }
        // 某个用户抢过了，不可以作弊重新抢
        return ResponseEntity.ok("errorCode:-2,   message: " + "\t" + userId + " 用户你已经抢过红包了");
    }

}
